#pragma once
#include <cstdint>
#include <mutex>
#include "ConfMgr.h"
#include "FIFOQueue.h"
#include "InnerType.h"
#include "XnccType.h"
#include "flat_hash_map"

namespace xncc {
namespace foundation {
    /// 对于一个业务线程来说，他需要的队列使用方式是，
    /// 假设业务线程  100 从订阅的QueueId = 1 里边读取数据, 那么业务线程100， 就必须知道 QueueId = 1 绑定的 eventfd，
    /// 然后注册这个fd的 读事件 假设业务线程  200  往 QueueId = 1 里边写了一条数据，那么
    /// 业务线程200写数据的时候只需要知道 QueueId 即可
    ///< 全局队列管理 管理一堆全局队列

    struct DynamicFIFOBuffer
    {
        msg::FIFOQueue::s_ptr QueueWrapper = {nullptr};
        std::mutex            mutex_;
        using s_ptr = std::shared_ptr<DynamicFIFOBuffer>;
    };

    class QueueManager
    {
      public:
        QueueManager() = default;
        ~QueueManager();

        QueueManager(const QueueManager&)             = delete;
        QueueManager(const QueueManager&&)            = delete;
        QueueManager& operator=(const QueueManager&)  = delete;
        QueueManager& operator=(const QueueManager&&) = delete;

        int init(const config::ConfMgr& cfg);
        /// 往某个全局队列发送数据
        int pubThreadData(const char* buf, uint32_t len, types::message_id_t id, types::thread_id_t tid);

        int pubThreadData(const char*         buf,
                          uint32_t            len,
                          types::message_id_t id,
                          types::thread_id_t  tid,
                          types::queue_id_t   bid);

        // IPC线程把数据发送到业务线程 tid 是IPC线程所在的id， connId是消息从哪个connId来的
        int pubIPCDataToBusiThread(const char*            buf,
                                   uint32_t               len,
                                   types::message_id_t    id,
                                   types::thread_id_t     tid,
                                   types::connection_id_t connId);
        /// 在代码中动态添加一个Queue 发送者直接发送数据即可
        auto subQueue(types::queue_id_t queueId, types::queue_size_t queueSize, bool autoExpand = false)
            -> msg::FIFOQueue::s_ptr;
        /// 发送者发送动态的Queue数据
        int dynamicPubTreadData(const char* buf, uint32_t len, types::message_id_t id, types::queue_id_t bid);
        /// 发送者发送动态的Queue数据
        int dynamicPubTreadDataWithLock(const char* buf, uint32_t len, types::message_id_t id, types::queue_id_t bid);

        // 订阅者 需要注册读事件
        auto getBusiThreadSubQueues(types::thread_id_t tid) -> std::vector<msg::FIFOQueue::s_ptr>;

        auto createIPCThreadRecvQueue(types::thread_id_t ioId, types::thread_id_t busiId) -> msg::FIFOQueue::s_ptr;

        int pubMsgToIPCThread(const char*            buf,
                              uint32_t               len,
                              types::thread_id_t     ioId,
                              types::thread_id_t     busiId,
                              types::connection_id_t connId,
                              types::message_id_t    ioMsgId,
                              types::message_id_t    id = shared::InnerMsgId::ON_PUB_IPC_MSG);

        [[nodiscard]] auto GetPubIds(types::thread_id_t tid) const -> const std::vector<types::queue_id_t>&;

      private:
        // 线程间通信，发数据动作
        static int sendMsgInThread(const msg::FIFOQueue::s_ptr& ptr,
                                   const char*                  buf,
                                   uint32_t                     len,
                                   types::message_id_t          id,
                                   types::connection_id_t       connId = types::FROM_OTHER_THREAD,
                                   types::thread_id_t           tid    = -1);

        // 线程间通信，发送数据到IPC线程
        static int sendMsgToIPCThread(const msg::FIFOQueue::s_ptr& ptr,
                                      const char*                  buf,
                                      uint32_t                     len,
                                      types::message_id_t          id,
                                      types::connection_id_t       connId,
                                      types::thread_id_t           tid);

        /*
         key 是 用户设置的bufferId
         value 是Queuebuffer
         代码中初始化生成的Queue-buffer， 不需要加锁访问
       */
        ska::flat_hash_map<types::queue_id_t, DynamicFIFOBuffer::s_ptr> DynamicBidBuffers_;
        /*
          IPC 线程接收业务线程发送的IPC数据的队列
          key IPC线程ID
          value  业务线程ID-> buffer
        */
        ska::flat_hash_map<types::thread_id_t, ska::flat_hash_map<types::thread_id_t, msg::FIFOQueue::s_ptr>>
            IPCRecvBuffers_;
        /*
         key 是 IPC线程的ID
         value  IPC线程所有的需要pub的buffer
         代码中初始化生成的Queue-buffer， 不需要加锁访问
       */
        ska::flat_hash_map<types::thread_id_t, std::vector<msg::FIFOQueue::s_ptr>> ioThreadPubQueues_;
        /*
         key 是 业务线程的ID
         value  业务线程所有的订阅的tcp线程的buffer
         代码中初始化生成的Queue-buffer， 不需要加锁访问
       */
        ska::flat_hash_map<types::thread_id_t, std::vector<msg::FIFOQueue::s_ptr>> busiThreadSubTcpQueues_;
        /*
          key 是 线程的ID
          value  发布数据的ID的集合
          代码中初始化生成的Queue-buffer， 不需要加锁访问
        */
        ska::flat_hash_map<types::thread_id_t, std::vector<types::queue_id_t>> threadPubIds_;

        /*
         key 是 发布的队列ID
         value  订阅发布队列ID的Queues
         代码中初始化生成的Queue-buffer， 不需要加锁访问
       */
        ska::flat_hash_map<types::queue_id_t, std::vector<msg::FIFOQueue::s_ptr>> pubidQueues_;
        /*
         key 是 业务线程的ID
         value  业务线程所有的订阅的业务线程buffer
         代码中初始化生成的Queue-buffer， 不需要加锁访问
       */
        ska::flat_hash_map<types::thread_id_t, std::vector<msg::FIFOQueue::s_ptr>> busiThreadSubBusiQueues_;
        /*
         key 是 消息ID
         value  消息ID的订阅对应的Queue
         代码中初始化生成的Queue-buffer， 不需要加锁访问
        */
        ska::flat_hash_map<types::message_id_t, std::vector<msg::FIFOQueue::s_ptr>> msgCodePubQueues_;
    };
}  // namespace foundation
}  // namespace xncc